Reads from read only parent disk images are intercepted, and are used to detect
authorKeir Fraser <keir.fraser@citrix.com>
Thu, 17 Dec 2009 06:27:57 +0000 (06:27 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Thu, 17 Dec 2009 06:27:57 +0000 (06:27 +0000)
potentially sharable memory pages.

Signed-off-by: Grzegorz Milos <Grzegorz.Milos@citrix.com>
tools/blktap2/drivers/Makefile
tools/blktap2/drivers/tapdisk-vbd.c
tools/blktap2/drivers/tapdisk.h
tools/memshr/interface.c
tools/memshr/memshr.h

index 97f27b56d3f5c21be6f43a7c2a3d6e14d2f2970f..b70ca7ddc03014a0368523d6d64bf61f37fdf944 100644 (file)
@@ -14,6 +14,7 @@ CFLAGS    += -Wno-unused
 CFLAGS    += -fno-strict-aliasing
 CFLAGS    += -I../lib -I../../libxc
 CFLAGS    += -I../include -I../../include
+CFLAGS    += $(CFLAGS_libxenctrl)
 CFLAGS    += -I $(LIBAIO_DIR)
 CFLAGS    += -I $(MEMSHR_DIR)
 CFLAGS    += -D_GNU_SOURCE
@@ -37,7 +38,7 @@ else
 CRYPT_LIB += -lcrypto
 endif
 
-LDFLAGS_img := $(CRYPT_LIB) -lpthread -lz -lm
+LDFLAGS_img := $(LDFLAGS_libxenctrl) $(CRYPT_LIB) -lpthread -lz -lm
 
 LIBS += -L$(LIBVHDDIR) -lvhd
 
index 07504cf7da3de19097225e7b7d495039d716ca68..14507b383062c38488c8e60c4a9132775812b36c 100644 (file)
@@ -1418,11 +1418,26 @@ tapdisk_vbd_complete_vbd_request(td_vbd_t *vbd, td_vbd_request_t *vreq)
        }
 }
 
+static uint64_t 
+tapdisk_vbd_breq_get_sector(blkif_request_t *breq, td_request_t treq)
+{
+    int seg, nsects; 
+    uint64_t sector_nr = breq->sector_number; 
+    
+    for(seg=0; seg < treq.sidx; seg++) {
+        nsects = breq->seg[seg].last_sect - breq->seg[seg].first_sect + 1;
+        sector_nr += nsects;
+    }
+
+    return sector_nr;
+}
+
 static void
 __tapdisk_vbd_complete_td_request(td_vbd_t *vbd, td_vbd_request_t *vreq,
                                  td_request_t treq, int res)
 {
        int err;
+    td_image_t *image = treq.image;
 
        err = (res <= 0 ? res : -res);
        vbd->secs_pending  -= treq.secs;
@@ -1440,7 +1455,18 @@ __tapdisk_vbd_complete_td_request(td_vbd_t *vbd, td_vbd_request_t *vreq,
                            (treq.op == TD_OP_WRITE ? "write" : "read"),
                            treq.secs, treq.sec);
                }
-       }
+       } else 
+    if(treq.op == TD_OP_READ && td_flag_test(image->flags, TD_OPEN_RDONLY)) {
+        uint64_t         hnd  = treq.memshr_hnd;
+        uint16_t         uid  = image->memshr_id;
+        blkif_request_t *breq = &vreq->req;
+        uint64_t         sec  = tapdisk_vbd_breq_get_sector(breq, treq);
+        int              secs = breq->seg[treq.sidx].last_sect -
+                                breq->seg[treq.sidx].first_sect + 1;
+
+        if(hnd != 0)
+            memshr_vbd_complete_ro_request(hnd, uid, sec, secs);
+    }
 
        tapdisk_vbd_complete_vbd_request(vbd, vreq);
 }
@@ -1492,7 +1518,29 @@ __tapdisk_vbd_reissue_td_request(td_vbd_t *vbd,
                break;
 
        case TD_OP_READ:
-               td_queue_read(parent, treq);
+        if(td_flag_test(parent->flags, TD_OPEN_RDONLY))
+        {
+            int ret, seg = treq.sidx;
+            blkif_request_t *breq = &vreq->req;
+        
+            ret = memshr_vbd_issue_ro_request(treq.buf,
+                                              breq->seg[seg].gref,
+                                              parent->memshr_id,
+                                              treq.sec,
+                                              treq.secs,
+                                              &treq.memshr_hnd);
+            if(ret == 0)
+            {
+                /* Reset memshr handle. This'll prevent
+                 * memshr_vbd_complete_ro_request being called */
+                treq.memshr_hnd = 0;
+                td_complete_request(treq, 0);
+            }
+            else
+                       td_queue_read(parent, treq);
+        }
+        else
+                   td_queue_read(parent, treq);
                break;
        }
 
index b1a91c77f27690a450f94ca96f8edc58c782731d..bd6835e5e8dc0a14ee995f7d399c04ad05a7be20 100644 (file)
@@ -131,6 +131,8 @@ struct td_request {
        uint64_t                     id;
        int                          sidx;
        void                        *private;
+    
+    uint64_t                     memshr_hnd;
 };
 
 /* 
index ad14bbf2a0a69ccd1ab55e5df19ea0ae3f3350c7..73fb144bfed4900b32c1ef0db7ffb6c72862d2a6 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 #include <string.h>
+#include <inttypes.h>
 
+#include "memshr.h"
 #include "memshr-priv.h"
+#include "bidir-hash.h"
 #include "shm.h"
 
 typedef struct {
     int     enabled;
     domid_t domid;
+    int     xc_handle;
 } memshr_vbd_info_t;
 
 memshr_vbd_info_t vbd_info = {0, DOMID_INVALID};
@@ -74,6 +78,8 @@ void memshr_daemon_initialize(void)
 
 void memshr_vbd_initialize(void)
 {
+    int xc_handle;
+
     memset(&memshr, 0, sizeof(private_memshr_info_t));
 
     if((SHARED_INFO = shm_shared_info_open(0)) == NULL)
@@ -103,6 +109,13 @@ void memshr_vbd_initialize(void)
     if(vbd_info.domid == DOMID_INVALID)
         return;
 
+    if((xc_handle = xc_interface_open()) < 0)
+    {
+        DPRINTF("Failed to open XC interface.\n");
+        return;
+    }
+
+    vbd_info.xc_handle = xc_handle;
     vbd_info.enabled = 1;
 }
 
@@ -125,4 +138,78 @@ void memshr_vbd_image_put(uint16_t memshr_id)
     shm_vbd_image_put(memshr_id, SHARED_INFO->vbd_images);
     if(pthread_mutex_unlock(&SHARED_INFO->lock)) return;
 }
+    
+int memshr_vbd_issue_ro_request(char *buf,
+                                grant_ref_t gref,
+                                uint16_t file_id, 
+                                uint64_t sec, 
+                                int secs,
+                                uint64_t *hnd)
+{
+    vbdblk_t blk;
+    uint64_t s_hnd, c_hnd;
+    int ret;
+
+    *hnd = 0;
+    if(!vbd_info.enabled) 
+        return -1;
+
+    if(secs != 8)
+        return -2;
+
+    /* Nominate the granted page for sharing */
+    ret = xc_memshr_nominate_gref(vbd_info.xc_handle,
+                                  vbd_info.domid,
+                                  gref,
+                                  &c_hnd);
+    /* If page couldn't be made sharable, we cannot do anything about it */
+    if(ret != 0)
+        return -3;
+    *hnd = c_hnd;
+
+    /* Check if we've read matching disk block previously */
+    blk.sec     = sec;
+    blk.disk_id = file_id;
+    if(blockshr_block_lookup(memshr.blks, blk, &s_hnd) > 0)
+    {
+        ret = xc_memshr_share(vbd_info.xc_handle, s_hnd, c_hnd);
+        if(!ret) return 0;
+        /* Handles failed to be shared => at least one of them must be invalid,
+           remove the relevant ones from the map */
+        switch(ret)
+        {
+            case XEN_DOMCTL_MEM_SHARING_S_HANDLE_INVALID:
+                ret = blockshr_shrhnd_remove(memshr.blks, s_hnd, NULL);
+                if(ret) DPRINTF("Could not rm invl s_hnd: %"PRId64"\n", s_hnd);
+                break;
+            case XEN_DOMCTL_MEM_SHARING_C_HANDLE_INVALID:
+                ret = blockshr_shrhnd_remove(memshr.blks, c_hnd, NULL);
+                if(ret) DPRINTF("Could not rm invl c_hnd: %"PRId64"\n", c_hnd);
+                break;
+            default:
+                break;
+        }
+        return -5;
+    }
+
+    return -4;
+}
+
+void memshr_vbd_complete_ro_request(uint64_t hnd,
+                                    uint16_t file_id, 
+                                    uint64_t sec, 
+                                    int secs)
+{
+    vbdblk_t blk;
+    
+    if(!vbd_info.enabled) 
+        return;
+
+    if(secs != 8)
+        return;
 
+    blk.sec     = sec;
+    blk.disk_id = file_id;
+    if(blockshr_insert(memshr.blks, blk, hnd) < 0)
+        DPRINTF("Could not insert block hint into hash.\n");
+}
index 1292d494f5458720cbed5a0ee13bc61aa75fe957..ae1449f091dda0133cbf8410d03c5a62023a4de3 100644 (file)
@@ -20,6 +20,8 @@
 #define __MEMSHR_H__
 
 #include <stdint.h>
+#include <xen/xen.h>
+#include <xen/grant_table.h>
 
 typedef uint64_t xen_mfn_t;
 
@@ -28,5 +30,16 @@ extern void memshr_daemon_initialize(void);
 extern void memshr_vbd_initialize(void);
 extern uint16_t memshr_vbd_image_get(char* file);
 extern void memshr_vbd_image_put(uint16_t memshr_id);
+extern int memshr_vbd_issue_ro_request(char *buf,
+                                       grant_ref_t gref,
+                                       uint16_t file_id, 
+                                       uint64_t sec, 
+                                       int secs,
+                                       uint64_t *hnd);
+extern void memshr_vbd_complete_ro_request(
+                                       uint64_t hnd,
+                                       uint16_t file_id, 
+                                       uint64_t sec, 
+                                       int secs);
 
 #endif /* __MEMSHR_H__ */